﻿using System;
using System.Collections.Generic;
#if DEBUG
using System.Diagnostics;
#endif // #if DEBUG
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;

using FRL.DebtChased.Extensions;
using FRL.DebtChased.WebServices;

namespace FRL.DebtChased.Repository
{

	/// <summary>
	/// Extensions to the ClientContact model
	/// </summary>
	public partial class ClientContact
	{

		/////////////////////////////////////////////////////////////
		// Static Operations

		public static Dictionary<int, string> LoadContactDictionary( DebtChasedEntities ent, int iClientId )
		{

			// Declare return variable
			Dictionary<int, string> Ftmp = new Dictionary<int, string>();

			// Loop through contacts
			var contacts = from cc in ent.ClientContacts
						   where cc.ClientId == iClientId
						   select new { cc.ClientContactId, cc.FullName };
			foreach (var contact in contacts)
				Ftmp.Add(contact.ClientContactId, contact.FullName);

			// Return variable
			return Ftmp;

		}

		public static List<ContactTransport> GetTransportList(Client client)
		{

			// Declare return variable
			List<ContactTransport> Ftmp = new List<ContactTransport>();

			// Loop through client contacts
			foreach (ClientContact cc in client.ClientContacts)
			{

				// Create transport object
				ContactTransport transport = ContactTransport.XmlFactory(cc.Xml);
				if (transport == null)
					throw new Exception("DebtChased internal error.  Cannot unwrap client contact.");
				transport.ContactId = cc.ClientContactId;
				transport.InUse = true;

				// Add to list
				Ftmp.Add(transport);

			}

			// Return variable
			return Ftmp;

		}

		public static ContactTransport GetTransport(DebtChasedEntities ent, int iClientContactId)
		{

			// Declare return variable
			ContactTransport Ftmp = null;

			// Load the contact
			ClientContact contact = ent.ClientContacts.FirstOrDefault( cc => (cc.ClientContactId == iClientContactId) );
			if (contact != null)
			{
				Ftmp = ContactTransport.XmlFactory(contact.Xml);
				if (Ftmp == null)
					throw new Exception("DebtChased internal error.  Cannot unwrap client contact.");
				Ftmp.ContactId = iClientContactId;
				Ftmp.InUse = true;
			}

			// Return variable
			return Ftmp;

		}

		public static void InterCursorSetFromTransport( 
			DebtChasedEntities ent,
			UserAction.Session session,
			Client currentClient, 
			ClientTransport clientTransport, 
			Dictionary<int, ClientContact> contactMap,
			int iUserId 
		)
		{

			// Check contacts and user details
			foreach (ContactTransport ct in clientTransport.Contacts)
			{
#if DEBUG
				Debug.Assert(ct.AddressList != null);
				Debug.Assert(ct.PointList != null);
#endif // #if DEBUG

				// Check the string lengths
				if ((string.IsNullOrEmpty(ct.Username)) || (ct.Username.Length < Definitions.MinUsernameLength))
					throw new Exception( string.Format("Account usernames require {0} characters.", Definitions.MinUsernameLength) );
				else if ((string.IsNullOrEmpty(ct.Password)) || (ct.Password.Length < Definitions.MinPasswordLength))
					throw new Exception(string.Format("Account passwords require {0} characters.", Definitions.MinPasswordLength));
				else if (
					(ct.UserRole != (int)Definitions.eRoles.CLIENT_ADMIN)
					&&
					(ct.UserRole != (int)Definitions.eRoles.CLIENT_USER)
				)
					throw new Exception("Client users must be CLIENT_USER or CLIENT_ADMIN.");
				else
				{

					// Check for existing username
					var user = (from u in ent.Users
								where (
									(u.Username == ct.Username) 
									&& 
									(
										(ct.ContactId == -1)
										||
										(
											(ct.ContactId != -1)
											&&
											(u.ClientContactId != ct.ContactId)
										)
									)
								)
								select u).FirstOrDefault();
					if (user != null)
						throw new Exception( string.Format("The username \"{0}\" is already in use.", ct.Username) );

				}

			}

			try
			{

				// Loop through the current contacts
				List<ClientContact> currentList = currentClient.ClientContacts.ToList();
				foreach (ClientContact currentContact in currentList)
				{

					// Find in the transport list
					ContactTransport transportContact = null;
					foreach (ContactTransport loop in clientTransport.Contacts)
					{
						if (loop.ContactId == currentContact.ClientContactId)
						{
							transportContact = loop;
							break;
						}
					}

					// If contact not found...
					if (transportContact == null)
					{

						// Delete the client-contact
						ent.DeleteObject(currentContact);

						// Delete the associated user
						User user = ent.Users.First(u => u.ClientContactId == currentContact.ClientContactId);
						ent.DeleteObject(user);

						// Update session
						session.AddChildDelta(currentContact, currentContact.FullName, null);
						session.AddChildDelta(user, currentContact.FullName, null);

					}
					else
					{

						// Update map
						contactMap.Add(transportContact.ContactId, currentContact);

						// Wrap the contact
						string strXml = transportContact.ToXml();

						// If contact has changed...
						if(strXml.CompareWithoutUnicodePrefix(currentContact.Xml,false)!=0)
						{

							// Update contact
							currentContact.SearchFields = transportContact.GetSearchFields();
							currentContact.Xml = strXml;

							// Update session
							session.AddChildDelta(currentContact, currentContact.FullName, null);

						}

						// If the user account has changed...
						User user = currentContact.tbUsers.FirstOrDefault();
						if (
							(string.Compare(user.Username, transportContact.Username, false) != 0)
							||
							(string.Compare(user.Password, transportContact.Password, false) != 0)
							||
							(user.fdRoles != transportContact.UserRole)
						)
						{

							// Update user
							user.Username = transportContact.Username;
							user.Password = transportContact.Password;
							user.fdRoles = transportContact.UserRole;

							// Update session
							session.AddChildDelta(user, currentContact.FullName, null);

						}

					}

				}

				// Add the new contacts
				foreach (ContactTransport transportContact in clientTransport.Contacts)
				{

					// Ignore all but new contacts
					if (transportContact.ContactId > 0)
						continue;

					// Add contact
					ClientContact newContact = ClientContact.CreateClientContact(
						0,
						0,
						transportContact.GetSearchFields(),
						transportContact.ToXml(),
						transportContact.ComposeFullName()
					);
					newContact.Client = currentClient;
					ent.ClientContacts.AddObject(newContact);

					// Add user account
					User user = User.CreateUser(0, transportContact.Username, transportContact.Password, transportContact.UserRole);
					user.ClientContact = newContact;
					ent.Users.AddObject(user);

					// Update session
					session.AddChildDelta(newContact, newContact.FullName, null);
					session.AddChildDelta(user, newContact.FullName, null);

					// Update map
					contactMap.Add(transportContact.ContactId, newContact);

				}

			}
			catch (Exception x)
			{

				// Process exception
				throw new Exception (ErrorProcessing.HandleException(x, "updating client contact", iUserId));

			}

		}

	}

	/// <summary>
	/// Extensions to the AgentContact model
	/// </summary>
	public partial class AgentContact
	{

		/////////////////////////////////////////////////////////////
		// Static Operations

		public static List<ContactTransport> GetTransportList(Agent agent)
		{

			// Declare return variable
			List<ContactTransport> Ftmp = new List<ContactTransport>();

			// Loop through agent contacts
			foreach (AgentContact ac in agent.AgentContacts)
			{

				// Create transport object
				ContactTransport transport = ContactTransport.XmlFactory(ac.Xml);
				if (transport == null)
					throw new Exception("DebtChased internal error.  Cannot unwrap agent contact.");
				transport.ContactId = ac.AgentContactId;
				transport.InUse = true;

				// Add to list
				Ftmp.Add(transport);

			}

			// Return variable
			return Ftmp;

		}

		public static void InterCursorSetFromTransport(
			DebtChasedEntities ent,
			UserAction.Session session,
			Agent currentAgent,
			AgentTransport agentTransport,
			Dictionary<int, AgentContact> contactMap,
			int iUserId
		)
		{

			// Check contacts
			foreach (ContactTransport ct in agentTransport.Contacts)
			{
#if DEBUG
				Debug.Assert(ct.AddressList != null);
				Debug.Assert(ct.PointList != null);
#endif // #if DEBUG
			}

			try
			{

				// Loop through the current contacts
				List<AgentContact> currentList = currentAgent.AgentContacts.ToList();
				foreach (AgentContact currentContact in currentList)
				{

					// Find in the transport list
					ContactTransport transportContact = null;
					foreach (ContactTransport loop in agentTransport.Contacts)
					{
						if (loop.ContactId == currentContact.AgentContactId)
						{
							transportContact = loop;
							break;
						}
					}

					// If contact not found...
					if (transportContact == null)
					{

						// Delete the agent-contact
						ent.DeleteObject(currentContact);

						// Update session
						session.AddChildDelta(currentContact, currentContact.FullName, null);

					}
					else
					{

						// Update map
						contactMap.Add(transportContact.ContactId, currentContact);

						// Wrap the contact
						string strXml = transportContact.ToXml();

						// If contact has changed...
						if (strXml.CompareWithoutUnicodePrefix(currentContact.Xml, false) != 0)
						{

							// Update contact
							currentContact.SearchFields = transportContact.GetSearchFields();
							currentContact.Xml = strXml;

							// Update session
							session.AddChildDelta(currentContact, currentContact.FullName, null);

						}

					}

				}

				// Add the new contacts
				foreach (ContactTransport transportContact in agentTransport.Contacts)
				{

					// Ignore all but new contacts
					if (transportContact.ContactId > 0)
						continue;

					// Add contact
					AgentContact newContact = AgentContact.CreateAgentContact(
						0,
						0,
						transportContact.GetSearchFields(),
						transportContact.ToXml(),
						transportContact.ComposeFullName()
					);
					newContact.Agent = currentAgent;
					ent.AgentContacts.AddObject(newContact);

					// Update session
					session.AddChildDelta(newContact, newContact.FullName, null);

					// Update map
					contactMap.Add(transportContact.ContactId, newContact);

				}

			}
			catch (Exception x)
			{

				// Process exception
				throw new Exception(ErrorProcessing.HandleException(x, "updating agent contact", iUserId));

			}

		}

	}

	/// <summary>
	/// Extensions to the AccountContact model
	/// </summary>
	public partial class AccountContact
	{

		/////////////////////////////////////////////////////////////
		// Static Operations

		public static List<ContactTransport> GetTransportList(Account account)
		{

			// Declare return variable
			List<ContactTransport> Ftmp = new List<ContactTransport>();

			// Loop through account contacts
			foreach (AccountContact ac in account.AccountContacts)
			{

				// Create transport object
				ContactTransport transport = ContactTransport.XmlFactory(ac.Xml);
				if (transport == null)
					throw new Exception("DebtChased internal error.  Cannot unwrap account contact.");
				transport.ContactId = ac.AccountContactId;
				transport.InUse = true;

				// Add to list
				Ftmp.Add(transport);

			}

			// Return variable
			return Ftmp;

		}

		public static List<ContactTransport> GetTransportList(DebtChasedEntities ent, int iAccountId)
		{

			// Declare return variable
			List<ContactTransport> Ftmp = new List<ContactTransport>();

			// Load account controls
			var contacts = from ac in ent.AccountContacts
							where ac.AccountId == iAccountId
							select ac;

			// Loop through account contacts
			foreach (AccountContact contact in contacts)
			{

				// Create transport object
				ContactTransport transport = ContactTransport.XmlFactory(contact.Xml);
				if (transport == null)
					throw new Exception("DebtChased internal error.  Cannot unwrap account contact.");
				transport.ContactId = contact.AccountContactId;
				transport.InUse = true;

				// Add to list
				Ftmp.Add(transport);

			}

			// Return variable
			return Ftmp;

		}

		public static void InterCursorSetFromTransport(
			DebtChasedEntities ent,
			Account currentAccount,
			AccountTransport accountTransport,
			int iUserId
		)
		{

			// Check contacts
			foreach (ContactTransport ct in accountTransport.DebtorContacts)
			{
#if DEBUG
				Debug.Assert(ct.AddressList != null);
				Debug.Assert(ct.PointList != null);
#endif // #if DEBUG
			}

			try
			{

				// Loop through the current contacts
				List<AccountContact> currentList = currentAccount.AccountContacts.ToList();
				foreach (AccountContact currentContact in currentList)
				{

					// Find in the transport list
					ContactTransport transportContact = null;
					foreach (ContactTransport loop in accountTransport.DebtorContacts)
					{
						if (loop.ContactId == currentContact.AccountContactId)
						{
							transportContact = loop;
							break;
						}
					}

					// If contact not found...
					if (transportContact == null)
					{

						// Delete the account-contact
						ent.DeleteObject(currentContact);

						// Update session
						//session.AddChildDelta(currentContact, currentContact.FullName, null);

					}
					else
					{

						// Wrap the contact
						string strXml = transportContact.ToXml();

						// If contact has changed...
						if (strXml.CompareWithoutUnicodePrefix(currentContact.Xml, false) != 0)
						{

							// Update contact
							currentContact.SearchFields = transportContact.GetSearchFields();
							currentContact.Xml = strXml;

							// Update session
							//session.AddChildDelta(currentContact, currentContact.FullName, null);

						}

					}

				}

				// Add the new contacts
				foreach (ContactTransport transportContact in accountTransport.DebtorContacts)
				{

					// Ignore all but new contacts
					if (transportContact.ContactId > 0)
						continue;

					// Add contact
					AccountContact newContact = AccountContact.CreateAccountContact(
						0,
						0,
						transportContact.ComposeFullName(),
						transportContact.GetSearchFields(),
						transportContact.ToXml()
						
					);
					newContact.Account = currentAccount;
					ent.AccountContacts.AddObject(newContact);

					// Update session
					//session.AddChildDelta(newContact, newContact.FullName, null);

				}

			}
			catch (Exception x)
			{

				// Process exception
				throw new Exception(ErrorProcessing.HandleException(x, "updating account contact", iUserId));

			}

		}

	}

}
